/*
 * Wire.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */

package engine;

import java.util.*;

/**
 * This is the class for the <code>wire</code> construct and all other
 * nets except trireg (@see Trireg).
 * @see WireDescription.
 */

@SuppressWarnings("serial")
class Wire extends BitVector{

	NameSpace ns;
	int expandType;
	Delay3 delays;
	WireDescription desc;  //runtime type information
	/**
	 * This makes the difference between wire, wand & stuff
	 */
	int truthTable[][];

	/**
	 * Here the strength will be kept; the 'strengths' layout is:
	 *<PRE>                       
	 *    n                                0 
	 *  +------------------------------------+ 
	 *  |   |        . . .               |   |   strengths
	 *  +-+--------------------------------+-+ 
	 *    |                                |  
	 *     \                                \ 
	 *       MSB in BitVector                 LSB in BitVector
	 *</PRE>
	 */   
	byte [] strength;
	int type;

	public Wire(NameSpace ns, WireDescription desc, int type,
			int nStart, int nEnd, int expandType, Delay3 delays){
		super(nStart, nEnd);
		this.ns = ns;
		this.desc = desc;
		this.expandType = expandType;
		this.delays = delays;
		strength = new byte[n];
		this.type = type;
		initToDefaults(this, strength);
		truthTable = lookupTables[type]; //see Assigneble for available types
	}

	public int getType() {
		return Symbol.wireType | Symbol.regType;
	}

	public int computeTransitionDelayFor(BitVector b) {
		return computeTransitionDelayFor(this, b, delays);
	}

	/**
	 * Returns the delay for the transition from the current
	 * value (before) to a given one (after).
	 */
	public static int computeTransitionDelayFor(BitVector before,
			BitVector after,
			Delay3 delays)
	{
		xConsole.debug("Wire's delays: " + delays.delay1Typ + " " + delays.delay2Typ +
				" " + delays.delay3Typ + " specs: " + delays.delaySpecs);
		xConsole.debug("before: " + before + " after: " + after);
		if(before.equals(after)){
			return 0;
		}

		switch(delays.delaySpecs){
		case 1:
			return delays.delay1Typ;
		case 2:
			if(!after.isX()){
				if(after.isZ())return Math.min(delays.delay1Typ, delays.delay2Typ);
				if(after.isNull())
					return delays.delay2Typ;    // !0 -> 0
					return delays.delay1Typ;       //0 -> !0
			}else
				return Math.min(delays.delay1Typ, delays.delay2Typ);   // ?? -> X
		case 3:
			if(!after.isX()){
				if(after.isZ())return delays.delay3Typ; // ?? -> Z
				if(after.isNull())
					return delays.delay2Typ;    // !0 -> 0
				return delays.delay1Typ;       //0 -> !0
			}else
				return Math.min(delays.delay3Typ,
						Math.min(delays.delay1Typ, delays.delay2Typ));   // ?? -> X
		}

		throw new Error("uncovered case in Wire.computeTransitionDelayFor: " +
				before + " -> " + after);
	}

	/**
	 * The improved version here is strength - aware
	 */
	synchronized Object[] compute() throws InterpretTimeException
	{
		BitVector b = new BitVector(this);
		byte newStrengths[] = new byte[b.n];
		initToDefaults(b, newStrengths);
		xConsole.debug("Wire.compute->");
		for(Enumeration e = data.elements() ; e.hasMoreElements() ; ){
			ContBitSelect bs = (ContBitSelect)e.nextElement();
			xConsole.debug("chunk: " + bs);
			for(int i = bs.start, inc = bs.start <= bs.end ? 1 : -1
					;; i += inc){
				xConsole.debug("i = " + i);
				int index = increment == 1 ? i - lsb : lsb - i;
				int result = Strength.reconcileDrivers(truthTable,
						newStrengths[index],
						bs.strength(i),
						b.getBit(i),
						bs.data.getBit(i));
				xConsole.debug("result: " + Integer.toHexString(result) );
				b.setBit(i, result >> 16);
				newStrengths[index] = (byte) (result & 0xff);
				if(i == bs.end)break;
			}
		}
		xConsole.debug("<-Wire.compute : b:" + b);
		Object [] res = {b, newStrengths};
		return res;
	}

	/**
	 * initializes this bitvector and strength 
	 * vector to the defaults for this type of net
	 */
	void initToDefaults(BitVector b, byte[] strengths)
	{
		xConsole.debug("initToDefaults: value is " +
				Assignable.initValDefaults[type]);
		int value = Assignable.initValDefaults[type];
		byte strength = Strength.initStrengthDefaults[type];
		for(int i = 0; i < b.n ; i++){
			b.setb(i, value);
			strengths[i] = strength;
		}
	}

	/**
	 * A Strengths - aware version of attrib
	 * Note that it assumes that valueas are obbtained from a 
	 * compue, and so they are correct - no checks are made here.
	 * @param b the new value of the wire (only the part in the
	 * range start: end is effectively assigned)
	 */
	void attrib(BitVector b, int start, int end, byte[] strengths)
	throws InterpretTimeException
	{
		xConsole.debug("Wire.attrib: " );
		for (int i = 0; i < strength.length; i++)
			xConsole.debug("strengths[" + i + "] = " +
					Strength.strengthToString(strengths[i], b.getb(i)));
		strength = strengths;
		attrib(start, end, b, start, end);
	}

	/**
	 * returns the strength and the value for 
	 * the given bit index, packed as an
	 * int like this:
	 * 
	 *  +--------------------------+
	 *  | value      |  strength   |
	 *  +--------------------------+
	 */
	int getValAndStrength(int bitIndex) {
		int i = increment == 1 ? bitIndex - lsb : lsb - bitIndex;
		return (getb(i) << 16) | strength[i];
	}

	byte getStrength(int bitIndex) {
		int i = increment == 1 ? bitIndex - lsb : lsb - bitIndex;
		return  strength[i];
	}
}













